﻿using AE.Net.Mail;
using System;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Timers;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
using ConfigLibrary;
using MailClient.Data.IndexTables;
using Microsoft.Exchange.WebServices.Authentication;
using Microsoft.Exchange.WebServices.Data;

namespace MailClient
{
	public class MailEntry
	{
		private readonly ArrayList _tree = new ArrayList();
		private Config config;
		private System.Timers.Timer tm;
		private static ExchangeService service;
		private static ImapClient emailClient;
		private static PropertySet emailprops;
		private static bool UsingExchange;

		/// <summary>
		/// Console entry point. Trys to use Exchange Web Services first then falls to standardized IMAP
		/// </summary>
		/// <param name="args">Not reading information from command line</param>
		public static void Main(string[] args)
		{
			try {
				UsingExchange = RunEWS();
				Console.Read();
			} catch {
				UsingExchange = !RunImap();
			}
		}
		
		static private bool RunEWS()
		{
			throw new Exception();
			// Constructor connects and logs in
			service = Mail.EWSConnection.connection.Service;
			emailprops = new PropertySet(
				ItemSchema.UniqueBody,
				ItemSchema.Categories
			);

			//MailClient.Queue.outgoingrunner.outgoing.SetImapClient (ref service);
			StreamingSubscription subscription = service.SubscribeToStreamingNotifications(
				new FolderId[] { WellKnownFolderName.Inbox },
				EventType.NewMail,
				EventType.Created,
				EventType.Deleted);
			StreamingSubscriptionConnection connection = new StreamingSubscriptionConnection(
				service,
				30
			);
			
			connection.AddSubscription(subscription);
			#if DEBUG
			Console.WriteLine("Subscriptions added");
			#endif
			// Delegate event handlers.
			connection.OnNotificationEvent +=
				new StreamingSubscriptionConnection.NotificationEventDelegate(OnEvent);
			connection.OnSubscriptionError +=
				new StreamingSubscriptionConnection.SubscriptionErrorDelegate(OnError);
			connection.OnDisconnect +=
				new StreamingSubscriptionConnection.SubscriptionErrorDelegate(OnDisconnect);
			connection.Open();
			#if DEBUG
			Console.WriteLine("EWS connection opened");
			#endif
			return true;
		}
		
		static private bool RunImap()
		{
			emailClient = Mail.ImapConnection.connection.client;
			Lazy<AE.Net.Mail.MailMessage>[] messages = emailClient.SearchMessages(AE.Net.Mail.SearchCondition.Unseen(), false, true);
			foreach (var email in messages) {
				ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessEmail), email);
			}
			return true;
		}

		static private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
		{
			// Cast the sender as a StreamingSubscriptionConnection object.
			StreamingSubscriptionConnection connection = (StreamingSubscriptionConnection)sender;
			// Ask the user if they want to reconnect or close the subscription.
			ConsoleKeyInfo cki;
			Console.WriteLine("The connection to the subscription is disconnected.");
			Console.WriteLine("Do you want to reconnect to the subscription? Y/N");
			while (true) {
				cki = Console.ReadKey(true);
				{
					if (cki.Key == ConsoleKey.Y) {
						connection.Open();
						Console.WriteLine("Connection open.");
						break;
					} else if (cki.Key == ConsoleKey.N) {
						// The ReadKey in the Main() consumes the E.
						Console.WriteLine("\n\nPress E to exit");
						break;
					}
				}
			}
		}

		static void OnEvent(object sender, NotificationEventArgs args)
		{
			StreamingSubscription subscription = args.Subscription;

			// Loop through all item-related events.
			foreach (NotificationEvent notification in args.Events) {
				// Determine the notification identifier.
				if (notification is ItemEvent) {
					// The NotificationEvent for an email message is an ItemEvent.
					ItemEvent itemEvent = (ItemEvent)notification;
					//                    Console.WriteLine("\nItemId: " + itemEvent.ItemId.UniqueId);
					switch (notification.EventType) {
						case EventType.NewMail:
							//                            Console.WriteLine("\n-------------Mail created:-------------");
							EmailMessage message = EmailMessage.Bind(
								service,
								itemEvent.ItemId,
								emailprops
							);
							Thread t = new Thread(ProcessEmail);
							t.Start(message);
							Console.WriteLine("new message: {0}", message.Subject);
							break;
						case EventType.Created:
							//                            Console.WriteLine("\n-------------Item created:-------------");
							break;
						case EventType.Deleted:
							//                            Console.WriteLine("\n-------------Item deleted:-------------");
							break;
					}
				} else {
					// The NotificationEvent for a folder is a FolderEvent.
					FolderEvent folderEvent = (FolderEvent)notification;
					//                    Console.WriteLine("\nFolderId: " + folderEvent.FolderId.UniqueId);
					switch (notification.EventType) {
						case EventType.NewMail:
							Console.WriteLine("\n-------------Mail created:-------------");
							break;
						case EventType.Created:
							//                            Console.WriteLine("\n-------------folder created:-------------");
							break;
						case EventType.Deleted:
							//                            Console.WriteLine("\n-------------folder deleted:-------------");
							break;
					}
				}
			}
		}

		static void OnError(object sender, SubscriptionErrorEventArgs args)
		{
			// Handle error conditions.
			Exception e = args.Exception;
			Console.WriteLine("\n-------------Error ---" + e.Message + "-------------");
		}

		private static void ProcessEmail(object mail)
		{
			AE.Net.Mail.MailMessage email = mail as AE.Net.Mail.MailMessage;
			ProcessEmail(email);
		}
		
		private static void ProcessEmail(EmailMessage mail)
		{
			MailClient.MailMessage email = new MailMessage(
				mail.From.Address,
				mail.ToRecipients [0].Address,
				mail.Subject,
				mail.UniqueBody.Text
			);
			ProcessEmail(email);
		}
		
		private static void ProcessEmail(AE.Net.Mail.MailMessage mail)
		{
			MailClient.MailMessage email = new MailMessage(
				mail.From.Address,
				mail.To.First().Address,
				mail.Subject,
				mail.Body
			);
			ProcessEmail(email);
		}
		
		private static void ProcessEmail(MailClient.MailMessage mail)
		{
			
			Queue.IncomingRunner incoming = new Queue.IncomingRunner(mail);
			incoming.CommandComplete += new Queue.IncomingRunner.CommandCompleteHandler(incoming_CommandComplete);
			incoming.Process();
		}

		private static	void incoming_CommandComplete(MailClient.Queue.MessageEventArgs e)
		{
			//TODO: embed calling object: incoming.CommandComplete -= new Queue.IncomingRunner.CommandCompleteHandler(incoming_CommandComplete);
			if (e.Response.Contains("This message is Spam")) {
				if (UsingExchange) {
					SendEmailViaEWS(e.Mail, true);
				} else {
					SendEmailViaIMAP(e.Mail, true);
				}
			} else {
				if (UsingExchange) {
					SendEmailViaEWS(e.Mail, false);
				} else {
					SendEmailViaIMAP(e.Mail, false);
				}
			}

			Thread.Sleep(300);
			NotSpamIndex.Index.Save();
			SpamIndex.Index.Save();
			MerchIndex.Index.Save();
			BrandIndex.Index.Save();
			CivilIndex.Index.Save();
			CityIndex.Index.Save();
			FuelIndex.Index.Save();
			GeoIndex.Index.Save();
			ShellIndex.Index.Save();
			WaterIndex.Index.Save();
			StoreIndex.Index.Save();
			PersonIndex.Index.Save();
		}
		
		private static void SendEmailViaEWS(MailClient.MailMessage email, bool Spam)
		{
			if (Spam) {
				EmailMessage message = new EmailMessage(service);
				message.ToRecipients.Add("bcrawford@rhaaia.com");
				message.Subject = string.Format("[SPAM] {0}", email.Subject);
				message.Body = "Body of orginial message is omitted from this email. Headers follow."
					+ "\r\n \r\n"
					+ email.InternetMessageHeaders;
				// TODO: get folder ID of e.Mail
				// TODO: move e.Mail to a temp junk folder
				message.Send();
			} else {
				EmailMessage ReplyMail = new EmailMessage(service);
				ReplyMail.ToRecipients.Add(email.From.Address);
				ReplyMail.Subject = email.Subject;
				ReplyMail.Body = email.Body;
			//	ReplyMail.Send();
			}
		}
		private static void SendEmailViaIMAP (MailClient.MailMessage email, bool Spam)
		{
			System.Net.Mail.SmtpClient smtpclient = new SmtpClient(Mail.ImapConnection.connection.client.Host,
			                                                       Mail.ImapConnection.connection.client.Port);
			smtpclient.UseDefaultCredentials = true;
			if (Spam) {
				smtpclient.Send("rha@rhaaia.com", "bcrawford@rhaaia.com", email.Subject,
				                "Body of orginial message is omitted from this email. Headers follow."
				                + "\r\n \r\n"
				                + email.InternetMessageHeaders);
				} else {
				//smtpclient.Send(email as System.Net.Mail.MailMessage);
			}
		}
	}
}
